#include "CSession.h"
#include "CServer.h"
#include <iostream>

// ????????socket?server?????????UUID
CSession::CSession(boost::asio::io_context &io_context, CServer *server) : _socket(io_context), _server(server)
{
	boost::uuids::uuid a_uuid = boost::uuids::random_generator()();
	_uuid = boost::uuids::to_string(a_uuid);
}

// ???????socket??
tcp::socket &CSession::GetSocket()
{
	return _socket;
}

// ???????UUID
std::string &CSession::GetUuid()
{
	return _uuid;
}

// ?????????????
void CSession::Start()
{
	memset(_data, 0, MAX_LENGTH);
	_socket.async_read_some(boost::asio::buffer(_data, MAX_LENGTH), std::bind(&CSession::HandleRead, this,
																			  std::placeholders::_1, std::placeholders::_2, shared_from_this()));
}

// ????????
// @param msg: ??????
// @param max_length: ??????
void CSession::Send(char *msg, int max_length)
{
	bool pending = false;
	std::lock_guard<std::mutex> lock(_send_lock);
	if (_send_que.size() > 0)
	{
		pending = true;
	}
	_send_que.push(make_shared<MsgNode>(msg, max_length));
	if (pending)
	{
		return;
	}

	boost::asio::async_write(_socket, boost::asio::buffer(msg, max_length),
							 std::bind(&CSession::HandleWrite, this, std::placeholders::_1, shared_from_this()));
}

// ????????????
// @param error: ???
// @param _self_shared: ???????
void CSession::HandleWrite(const boost::system::error_code &error, shared_ptr<CSession> _self_shared)
{
	if (!error)
	{
		std::lock_guard<std::mutex> lock(_send_lock);
		_send_que.pop();
		if (!_send_que.empty())
		{
			auto &msgnode = _send_que.front();
			boost::asio::async_write(_socket, boost::asio::buffer(msgnode->_data, msgnode->_max_len),
									 std::bind(&CSession::HandleWrite, this, std::placeholders::_1, _self_shared));
		}
	}
	else
	{
		std::cout << "handle write failed, error is " << error.message() << endl;
		_server->ClearSession(_uuid);
	}
}

// ????????????
// @param error: ???
// @param bytes_transferred: ?????????
// @param _self_shared: ???????
void CSession::HandleRead(const boost::system::error_code &error, size_t bytes_transferred, shared_ptr<CSession> _self_shared)
{
	if (!error)
	{
		cout << "read data is " << _data << endl;
		// ??????????echo??????
		Send(_data, bytes_transferred);
		memset(_data, 0, MAX_LENGTH);
		_socket.async_read_some(boost::asio::buffer(_data, MAX_LENGTH), std::bind(&CSession::HandleRead, this,
																				  std::placeholders::_1, std::placeholders::_2, _self_shared));
	}
	else
	{
		std::cout << "handle read failed, error is " << error.message() << endl;

		_server->ClearSession(_uuid);
	}
}
